/*
 *    Copyright (c) 2018-2025, proj All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the proj developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: proj
 */
package com.ykht.proj.activity.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ykht.proj.activity.constant.CardConstant;
import com.ykht.proj.activity.entity.*;
import com.ykht.proj.activity.mapper.VCardMapper;
import com.ykht.proj.activity.mapper.VInfoMapper;
import com.ykht.proj.activity.service.VCardService;
import com.ykht.proj.activity.service.VDiscountPlanService;
import com.ykht.proj.activity.service.VInfoService;
import com.ykht.proj.activity.vo.*;
import com.ykht.proj.common.core.constant.CommonConstants;
import com.ykht.proj.common.core.util.R;
import com.ykht.proj.common.security.util.SecurityUtils;
import com.ykht.proj.coupon.api.feign.RemotePersonService;
import com.ykht.proj.coupon.api.feign.RemoteShopService;
import com.ykht.proj.coupon.entity.CnPerson;
import com.ykht.proj.coupon.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 持卡人表（会员卡）
 *
 * @author csg
 * @date 2021-05-21 14:22:59
 */
@Service
@Slf4j
public class VInfoServiceImpl extends ServiceImpl<VInfoMapper, VInfo> implements VInfoService {

	@Resource
	private VInfoMapper vInfoMapper;
	@Resource
	private RemotePersonService remotePersonService;
	@Resource
	private RemoteShopService remoteShopService;
	@Resource
	private VDiscountPlanService vDiscountPlanService;
	@Resource
	private VCardService vCardService;



	@Override
	@Transactional(rollbackFor = Exception.class)
	public R exchange(String code) {

		log.info("->验证用户");
		R<CnPerson> r = remotePersonService.getPersonById(SecurityUtils.getPersonId());
		if (CommonConstants.SUCCESS!=r.getCode()) return R.failed("用户异常");
		CnPerson person = r.getData();
		if (null==person.getPhone()) return R.failed("用户未授权手机号");
		if (0!=person.getStatus()) return R.failed("用户状态异常");

		VOrderCard orderCard = new VOrderCard().selectOne(Wrappers.lambdaQuery(VOrderCard.class).eq(VOrderCard::getRedeemCode,code.trim()));
		if (orderCard == null) return R.failed("无效的兑换码");
		if (orderCard.getCardStatus()!= CardConstant.CARD_STATUS_WDH) return R.failed("兑换码已使用过");

		log.info("->更新订单卡表");
		//更新订单卡表
		orderCard.setCardStatus(CardConstant.CARD_STATUS_YJH);//已激活
		orderCard.setPersonId(person.getId());
		orderCard.setPersonName(person.getNickName());
		orderCard.setPersonPhone(person.getPhone());
		orderCard.updateById();

		VCard card = new VCard().selectById(orderCard.getCardId());
		//给卡添加激活数量+1
		vCardService.updateActivationVolume(card.getId());

		log.info("->添加会员卡");
		//添加会员表
		VInfo info = new VInfo();
		info.setEntId(orderCard.getEnterpriseId());
		info.setEntStaffName(orderCard.getPersonName());
		info.setCType(card.getType());
		info.setActivityId(orderCard.getActivityId());
		info.setCardId(orderCard.getCardId());
		info.setOrderCardId(orderCard.getId());
		info.setPersonId(orderCard.getPersonId());
		info.setStatus(0);
		info.setOpenCardTime(LocalDateTime.now());
		String vipAccount = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))+ RandomUtil.randomNumbers(4);
		info.setVipAccount(vipAccount);//卡号
		String useCode = String.valueOf(System.currentTimeMillis()).substring(5, 13);
		info.setUseCode(useCode);//核销码
		info.setTotalActMoney(BigDecimal.ZERO);//累计消费金额
		info.setTotalMoney(BigDecimal.ZERO);//累计实付金额
		//使用有效类型: 0自开卡之日起X天有效  1时间范围  2 无期限
		switch (card.getUseEffectiveType()){
			case 0:
				info.setStartTime(LocalDateTime.now());
				if (card.getEffectiveDays()!=null){
					info.setEndTime(LocalDateTime.of(LocalDateTime.now().toLocalDate(), LocalTime.MAX.withNano(0)).plusDays(card.getEffectiveDays()-1));
				}
				break;
			case 1:
				info.setStartTime(card.getStaTime());
				info.setEndTime(card.getEndTime());
				break;
			case 2:
				info.setStartTime(LocalDateTime.now());
				info.setEndTime(card.getEndTime());
				break;
		}

		info.setCreateTime(LocalDateTime.now());
		info.setCreateUser(orderCard.getPersonId());
		info.setUseNum(0);
		info.insert();
		return R.ok();
	}

	@Override
	public VInfoCard getInfoById(Long id) {
		VInfoCard infoCard = new VInfoCard();
		VInfo v = new VInfo().selectById(id);
		VCard card = new VCard().selectById(v.getCardId());
		VOrderCard orderCard = new VOrderCard().selectById(v.getOrderCardId());
		infoCard.setV(v);
		infoCard.setCard(card);
		infoCard.setOrderCard(orderCard);
		if (orderCard.getEnterpriseId()!=null){
			VEnt ent = new VEnt().selectById(orderCard.getEnterpriseId());
			infoCard.setEnt(ent);
		}
		return infoCard;
	}

	@Override
	public R<Page<ShopPlan>> shopPage(Page<ShopPlan> page, Long id, BaseLonLat lonLat) {
		VInfo v = new VInfo().selectById(id);
		VCard card = new VCard().selectById(v.getCardId());

		//所有分组
		List<Long> groupIds = new VCardGroup().selectList(Wrappers.lambdaQuery(VCardGroup.class)
				.select(VCardGroup::getGroupId)
				.eq(VCardGroup::getCardId,v.getCardId()))
				.stream().map(VCardGroup::getGroupId).collect(Collectors.toList());
		if (groupIds.size()==0) return R.ok(page);
		//所有门店
		List<Long> shopIds = new VGroupShop().selectList(Wrappers.lambdaQuery(VGroupShop.class).select(VGroupShop::getShopId).in(VGroupShop::getGroupId,groupIds)).stream().map(VGroupShop::getShopId).collect(Collectors.toList());


		if (card.getDiscountType()==CardConstant.DISCOUNT_TYPE_BF){
			shopIds = new VOrderCardShop().selectList(Wrappers.lambdaQuery(VOrderCardShop.class)
							.select(VOrderCardShop::getShopId)
							.eq(VOrderCardShop::getOrderCardId,v.getOrderCardId())
							.eq(VOrderCardShop::getCurrentStatus,0))
					.stream().map(VOrderCardShop::getShopId).collect(Collectors.toList());

		}

		//远程分页门店信息
		AboutShopReq req = new AboutShopReq();
		req.setPage(page);
		req.setIds(shopIds);
		req.setLatitude(lonLat.getLatitude());
		req.setLongitude(lonLat.getLongitude());
		Page<AboutShopVo> tempPage = remoteShopService.shopByIds(req);

		//协议相关
		VPlanInfoReq vPlanInfoReq = new VPlanInfoReq();
		vPlanInfoReq.setShopIds(shopIds);
		List<VPlanInfo> planInfoList = vDiscountPlanService.getPlanInfo(vPlanInfoReq);
		Map<Long,VPlanInfo> map = planInfoList.stream().collect(Collectors.toMap(o->o.getDps().getShopId(), Function.identity(), (key1, key2) -> key2));

		//组装数据
		List<ShopPlan> list = tempPage.getRecords().stream().map(o->{
			ShopPlan vo = new ShopPlan();
			ShopInfo shopInfo = BeanUtil.toBean(o,ShopInfo.class);
			vo.setShopInfo(shopInfo);
			vo.setInfo(map.getOrDefault(o.getShopId(),new VPlanInfo()));
			return vo;
		}).collect(Collectors.toList());
		page.setRecords(list);
		return R.ok(page);
	}

	/**
	 * 我的卡
	 * @param lonLat
	 * @return
	 */
	@Override
	public R<VInfoBySelfVo> getListBySelf(BaseLonLat lonLat,Integer status) {
		VInfoBySelfVo vo = new VInfoBySelfVo();
		List<VInfo> vInfos = new VInfo().selectList(Wrappers.lambdaQuery(VInfo.class).eq(VInfo::getPersonId,SecurityUtils.getPersonId()).eq(status!=null,VInfo::getStatus,status));
		Integer unExpireNum = new VInfo().selectCount(Wrappers.lambdaQuery(VInfo.class).eq(VInfo::getPersonId,SecurityUtils.getPersonId()).eq(VInfo::getStatus,0));
		Integer expireNum = new VInfo().selectCount(Wrappers.lambdaQuery(VInfo.class).eq(VInfo::getPersonId,SecurityUtils.getPersonId()).eq(VInfo::getStatus,1));
		vo.setExpireNum(expireNum);
		vo.setUnexpireNum(unExpireNum);
		//所有卡关联的门店
		R<List<CnShopDisVo>> r = remoteShopService.distanceList(new ShopDisListVo(lonLat,null));
		if (r.getCode() != CommonConstants.SUCCESS) return R.ok(vo);
		List<CnShopDisVo> shopDisVoList = r.getData();
		List<Long> cardIds = vInfos.stream().map(VInfo::getCardId).collect(Collectors.toList());

		//所有卡关联的门店
		List<CardShopVo> cardShopVoList = vCardService.shopByCardIds(cardIds);
		//所有卡里的所有门店
		List<CardPlanInfo> planInfoList = vDiscountPlanService.getCardPlanInfo(cardShopVoList,shopDisVoList);
		Map<Long,CardPlanInfo > planInfoMap = planInfoList.stream().collect(Collectors.toMap(o->o.getCard().getId(), Function.identity(), (key1, key2) -> key2));
		List<VInfoBySelf> vList = vInfos.stream().map(o->{
			VInfoBySelf v = new VInfoBySelf();
			//会员卡
			v.setVInfo(o);
			//距离
			planInfoMap.getOrDefault(o.getCardId(),new CardPlanInfo()).getShopPlanList().stream()
					.filter(oo->oo.getShopInfo().getDistance()!=null)
					.sorted(Comparator.comparing(oo->oo.getShopInfo().getDistance()))
					.mapToLong(oo->oo.getShopInfo().getDistance())
					.findFirst().ifPresent(oo->v.setDistance(oo));
			//卡
			v.setVCard(planInfoMap.getOrDefault(o.getCardId(),new CardPlanInfo()).getCard());
			VOrderCard vOrderCard = new VOrderCard().selectById(o.getOrderCardId());
			//订单和联名卡信息
			v.setVOrderCard(vOrderCard);
			//企业logo
			if (null != vOrderCard.getEnterpriseId()){
				VEnt vEnt = new VEnt().selectById(vOrderCard.getEnterpriseId());
				v.setEnt(vEnt);
			}
			return v;
		}).sorted(Comparator.comparing(VInfoBySelf::getDistance,Comparator.nullsLast(Long::compareTo))//距离升序
				.thenComparing(o->o.getVInfo().getOpenCardTime(),Comparator.nullsLast(Comparator.reverseOrder())))//距离一致按购卡时间倒序
				.collect(Collectors.toList());
		vo.setList(vList);
		return R.ok(vo);
	}


	/**
	 * 开卡记录（持卡人表（会员卡）） 分页查询
	 *
	 * @param page   分页
	 * @param infoVo 条件
	 * @return
	 */
	@Override
	public IPage<VInfoVo> getVInfoPage(Page page, VInfoVo infoVo) {
		return vInfoMapper.getVInfoPage(page, infoVo);
	}


	/**
	 * 核销卡 给会员卡 添加次数
	 *
	 * @param info
	 */
	@Override
	public void updateInfo(VInfo info) {
		vInfoMapper.updateInfo(info);
	}

	@Override
	public R<List<VCardInfo.ShopVo>> cardShopList(Long vId, BaseLonLat lonLat) {
		VInfo vInfo = new VInfo().selectById(vId);
		if (vInfo==null) return R.failed("会员卡不存在");
		List<VCardInfo.ShopVo> shopVoList = vCardService.shopVoListByVId(lonLat,vId,vInfo.getCardId());
		if (BeanUtil.isNotEmpty(lonLat)){
			//可用门店列表：默认距离优先，次数已用完的门店放在后面；
			shopVoList = shopVoList.stream().sorted(Comparator.comparing(VCardInfo.ShopVo::getDistance,Comparator.nullsLast(Long::compareTo)).thenComparing(VCardInfo.ShopVo::getUseNum,Comparator.reverseOrder())).collect(Collectors.toList());
		}else {
			// 没有地里位置授权的，按折扣优先；
			shopVoList = shopVoList.stream().filter(o->o.getPlan()!=null).sorted(Comparator.comparing(o->o.getPlan().getDiscount())).collect(Collectors.toList());
		}
		return R.ok(shopVoList);
	}

	/**
	 * 企业  绑定卡
	 *
	 * @param vOrderCardVo
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R entBinDingCard(VOrderCardVo vOrderCardVo) {

		log.info("->验证用户");
		R<CnPerson> r = remotePersonService.getByPhone(vOrderCardVo.getPersonPhone());
		if (CommonConstants.SUCCESS!=r.getCode()) return R.failed("手机号格式错误");
		CnPerson person = r.getData();
		if (null == person) return R.failed("此手机号不是吃哈哈注册用户，请注册再绑定");
		if (0!=person.getStatus()) return R.failed("用户状态异常");

		VOrderCard orderCard = new VOrderCard().selectOne(Wrappers.lambdaQuery(VOrderCard.class).eq(VOrderCard::getRedeemCode, vOrderCardVo.getRedeemCode()));
		if (orderCard == null) return R.failed("此卡已兑换");
		if (orderCard.getCardStatus()!= CardConstant.CARD_STATUS_WDH) return R.failed("此卡已兑换");

		log.info("->更新订单卡表");
		//更新订单卡表
		orderCard.setCardStatus(CardConstant.CARD_STATUS_YJH);//已激活
		orderCard.setPersonId(person.getId());
		orderCard.setPersonPhone(person.getPhone());
		orderCard.setPersonName(person.getNickName());
		orderCard.updateById();

		VCard card = new VCard().selectById(orderCard.getCardId());
		log.info("->添加会员卡");
		//添加会员表
		VInfo info = new VInfo();
		info.setEntId(orderCard.getEnterpriseId());
		info.setEntStaffName(vOrderCardVo.getPersonName());
		info.setCType(card.getType());
		info.setActivityId(orderCard.getActivityId());
		info.setCardId(orderCard.getCardId());
		info.setOrderId(orderCard.getOrderId());
		info.setOrderCardId(orderCard.getId());
		info.setPersonId(orderCard.getPersonId());
		info.setStatus(0);
		info.setOpenCardTime(LocalDateTime.now());
		String vipAccount = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))+ RandomUtil.randomNumbers(4);
		info.setVipAccount(vipAccount);//卡号
		String useCode = String.valueOf(System.currentTimeMillis()).substring(5, 13);
		info.setUseCode(useCode);//核销码
		info.setTotalActMoney(BigDecimal.ZERO);//累计消费金额
		info.setTotalMoney(BigDecimal.ZERO);//累计实付金额
		info.setUseNum(0);
		//使用有效类型: 0自开卡之日起X天有效  1时间范围  2 无期限
		switch (card.getUseEffectiveType()){
			case 0:
				info.setStartTime(LocalDateTime.now());
				if (card.getEffectiveDays()!=null){
					info.setEndTime(LocalDateTime.of(LocalDateTime.now().toLocalDate(), LocalTime.MAX.withNano(0)).plusDays(card.getEffectiveDays()-1));
				}
				break;
			case 1:
				info.setStartTime(card.getStaTime());
				info.setEndTime(card.getEndTime());
				break;
			case 2:
				info.setStartTime(LocalDateTime.now());
				info.setEndTime(card.getEndTime());
				break;
		}

		info.setCreateTime(LocalDateTime.now());
		info.setCreateUser(orderCard.getPersonId());
		info.insert();
		// 企业绑定卡  给卡添加激活数量+1
		vCardService.updateActivationVolume(card.getId());
		return R.ok();
	}

	/**
	 * 开卡记录 卡信息
	 *
	 * @param id
	 * @return
	 */
	@Override
	public VInfoVo getByIdInfoDetails(Long id) {
		return vInfoMapper.getByIdInfoDetails(id);
	}
}
